package it.ap.sa.acqua.tank.service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import it.ap.sa.acqua.dao.beans.LivestockBean;
import it.ap.sa.acqua.dao.beans.SearchTankFilter;
import it.ap.sa.acqua.dao.beans.TAssTankFishBean;
import it.ap.sa.acqua.dao.beans.TAssTankPlantBean;
import it.ap.sa.acqua.dao.beans.TTankBean;
import it.ap.sa.acqua.dao.beans.TTankTypeAlertBean;
import it.ap.sa.acqua.dao.impl.TAssTankFishDao;
import it.ap.sa.acqua.dao.impl.TAssTankPlantDao;
import it.ap.sa.acqua.dao.impl.TFishDao;
import it.ap.sa.acqua.dao.impl.TFishImageDao;
import it.ap.sa.acqua.dao.impl.TPlantDao;
import it.ap.sa.acqua.dao.impl.TPlantImageDao;
import it.ap.sa.acqua.dao.impl.TTankAlertDao;
import it.ap.sa.acqua.dao.impl.TTankDao;
import it.ap.sa.acqua.dao.impl.TTankTypeAlertDao;
import it.ap.sa.acqua.dao.model.TAssTankFish;
import it.ap.sa.acqua.dao.model.TAssTankPlant;
import it.ap.sa.acqua.dao.model.TFish;
import it.ap.sa.acqua.dao.model.TFishImage;
import it.ap.sa.acqua.dao.model.TPlant;
import it.ap.sa.acqua.dao.model.TPlantImage;
import it.ap.sa.acqua.dao.model.TTank;
import it.ap.sa.acqua.dao.model.TTankAlert;
import it.ap.sa.acqua.dao.model.TTankTypeAlert;
import it.ap.sa.core.util.IBeanPopulate;
import it.ap.sa.core.utils.ListUtils;

/**
 * @author Alessandro Paolillo
 */
@Service
public class TankService implements ITankService {

	private static final Logger logger = LoggerFactory.getLogger(TankService.class.getName());

	@Autowired
	private IBeanPopulate<TTank, TTankBean> tankConverter;
	
	@Autowired
	private IBeanPopulate<TTankTypeAlert, TTankTypeAlertBean> tankTypeAlertConverter;
	
	@Autowired
	private IBeanPopulate<TAssTankFish, TAssTankFishBean> assTankFishConverter;
	
	@Autowired
	private IBeanPopulate<TAssTankPlant, TAssTankPlantBean> assTankPlantConverter;
	
	@Autowired
	private TTankDao tTankDao;
	
	@Autowired
	private TFishDao tFishDao;
	
	@Autowired
	private TFishImageDao tFishImageDao;
	
	@Autowired
	private TPlantDao tPlantDao;
	
	@Autowired
	private TPlantImageDao tPlantImageDao;
	
	@Autowired
	private TTankAlertDao tTankAlertDao;
	
	@Autowired
	private TTankTypeAlertDao tTankTypeAlertDao;
	
	@Autowired
	private TAssTankFishDao tAssTankFishDao;

	@Autowired
	private TAssTankPlantDao tAssTankPlantDao;
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public TTankBean getTank(Long id) throws Exception {
		
		TTankBean result = new TTankBean();
		try {
			
			
//			TTank entity = tTankDao.findByPk( id ); 
//			if (entity!=null)
//				result = this.tankConverter.convertdbToPage(entity);
			logger.info("Query eseguita correttametne");
		} catch(Exception e){
			logger.error("getTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return result;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public List<TTankBean> getTanks( ) throws Exception {
		
		List<TTankBean> resultList = new ArrayList<TTankBean>();
		try {
			
			
//			List<TTank> list = tTankDao.getAll(  );
//			if(ListUtils.listIsNotEmpty(list)) 
//				for (TTank entity : list) 
//					resultList.add(this.tankConverter.convertdbToPage(entity));
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("getTanks >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return resultList;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public TTankBean saveTank( TTankBean tankBean ) throws Exception {
		
		try {
			
			/*Salvataggio vasca*/
			TTank entity = tTankDao.saveOrUpdate( tankConverter.convertpageToDb(tankBean) );
				/*Salvataggio avvisi*/
				tTankAlertDao.deleteByIdTank(entity.getId());
				if(ListUtils.listIsNotEmpty( tankBean.getTankTypes() )) {
					for (TTankTypeAlertBean tTankTypeAlertBean : tankBean.getTankTypes() ) {
						if ( tTankTypeAlertBean.getSelected()!=null && tTankTypeAlertBean.getSelected() ) {
							TTankAlert tTankAlert = new TTankAlert();
							tTankAlert.setIdTank( entity.getId() );
							tTankAlert.setIdTypeAlert( tTankTypeAlertBean.getId() );
							tTankAlert.setTypeAlert( tTankTypeAlertBean.getNome() );
							LocalDateTime dateTime = LocalDateTime.now();
							tTankAlert.setDateNextOperation(dateTime);
							tTankAlertDao.saveOrUpdate(tTankAlert);
						}
					}
				}
			if (entity!=null)
				tankBean = tankConverter.convertdbToPage( entity );
			
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("saveTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return tankBean;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public void deleteTank( TTankBean tankBean ) throws Exception {
		
		try {
			
			/** Elimino avvisi **/
			tTankAlertDao.deleteByIdTank(tankBean.getId());
			/** Elimino vasca**/
			tTankDao.deleteById(tankBean.getId(), tankBean.getIdUser());
			
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("deleteTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public List<TTankBean> searchTank( SearchTankFilter searchTankFilter) throws Exception {
		
		List<TTankBean> resultList = new ArrayList<TTankBean>();
		try {
			List<TTank> list = tTankDao.searchTank( searchTankFilter );
			if(ListUtils.listIsNotEmpty(list)) 
				for (TTank entity : list) {
					TTankBean bean = this.tankConverter.convertdbToPage(entity);
					
					List<TTankTypeAlertBean> resultTankTypeList = new ArrayList<TTankTypeAlertBean>();
					List<TTankAlert> tankList = tTankAlertDao.getTankAlertsByIdTank( entity.getId() ); /** alert legati alla vasca **/
					List<TTankTypeAlert> tankTypeList = tTankTypeAlertDao.getTankTypeAlerts();
					if(ListUtils.listIsNotEmpty( tankTypeList )) {	
						for ( TTankTypeAlert entityTankType : tankTypeList ) {
							TTankTypeAlertBean beanTankType = this.tankTypeAlertConverter.convertdbToPage(entityTankType);
							if(ListUtils.listIsNotEmpty( tankList )) {
								for ( TTankAlert entityTankAlert : tankList )
									if ( entityTankAlert.getIdTypeAlert()==entityTankType.getId())
										beanTankType.setSelected(true);
							} else
								beanTankType.setSelected(false);
							resultTankTypeList.add( beanTankType );
						}
						bean.setTankTypes( resultTankTypeList );
					}
					resultList.add(bean);
				}
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("searchTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return resultList;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public Long searchCountTank( SearchTankFilter searchTankFilter) throws Exception {
		
		Long searchCountTankValue = new Long(0);
		try {
			searchCountTankValue = tTankDao.searchCountTank( searchTankFilter );
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("searchCountTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return searchCountTankValue;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public List<TTankBean> myTanks( SearchTankFilter searchTankFilter) throws Exception {
		
		List<TTankBean> resultList = new ArrayList<TTankBean>();
		try {
			List<TTank> list = tTankDao.searchTank( searchTankFilter );
			if(ListUtils.listIsNotEmpty(list)) 
				for (TTank entity : list) {
					resultList.add( this.tankConverter.convertdbToPage(entity) );
				}
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("myTanks >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return resultList;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public Long myCountTank( SearchTankFilter searchTankFilter) throws Exception {
		
		Long searchCountTankValue = new Long(0);
		try {
			searchCountTankValue = tTankDao.searchCountTank( searchTankFilter );
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("myCountTank >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return searchCountTankValue;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public List<TTankTypeAlertBean> getTankTypes( ) throws Exception {
		
		List<TTankTypeAlertBean> resultList = new ArrayList<TTankTypeAlertBean>();
		try {
			
			List<TTankTypeAlert> list = tTankTypeAlertDao.getTankTypeAlerts();
			if(ListUtils.listIsNotEmpty(list)) 
				for (TTankTypeAlert entity : list) 
					resultList.add(this.tankTypeAlertConverter.convertdbToPage(entity));
				
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("getTankTypes >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return resultList;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public List<LivestockBean> getLivestock( long tankId ) throws Exception {
		
		List<LivestockBean> resultList = new ArrayList<LivestockBean>();
		try {
			
			/** RECUPERO PESCI **/
			List<TAssTankFish> listFish = tAssTankFishDao.findByIdTank( tankId );
			if(ListUtils.listIsNotEmpty(listFish)) 
				for (TAssTankFish entity : listFish) {
					LivestockBean lBean = new LivestockBean();
					TFish entityFish  = tFishDao.findByPk(entity.getIdFish());
					lBean.setId(entityFish.getId());
					lBean.setCommonName(entityFish.getCommonName());
					lBean.setType("Fish");
					lBean.setTankId(tankId);
					TFishImage entityFishImage = tFishImageDao.findByIdFish(entity.getIdFish());
					lBean.setUrlImage(entityFishImage!=null ? "images/fishs/"+entityFishImage.getUrl()+".jpg" : "");
					resultList.add(lBean);
				}
			
			/** RECUPERO PIANTE **/
			List<TAssTankPlant> listPlant = tAssTankPlantDao.findByIdTank( tankId );
			if(ListUtils.listIsNotEmpty(listPlant)) 
				for (TAssTankPlant entity : listPlant){
					LivestockBean lBean = new LivestockBean();
					TPlant entityPlant  = tPlantDao.findByPk(entity.getIdPlant());
					lBean.setId(entityPlant.getId());
					lBean.setCommonName(entityPlant.getScientificName());
					lBean.setType("Plant");
					lBean.setTankId(tankId);
					TPlantImage entityPlantImage = tPlantImageDao.findByIdPlant(entity.getIdPlant());
					lBean.setUrlImage(entityPlantImage!=null ? "images/plants/"+entityPlantImage.getUrl()+".jpg" : "");
					resultList.add(lBean);
				}
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("getLivestock >>>>>>>>>>>> " + e, e);
			throw(e);
		}
		return resultList;
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public void saveLivestock( LivestockBean livestockBean ) throws Exception {
		
		try {
			
			if (livestockBean.getType().equals("Fish")) {							/** AGGIUNGO PESCE **/
				
				TAssTankFish entity = new TAssTankFish();
				entity.setIdFish( livestockBean.getId() );
				entity.setIdTank( livestockBean.getTankId() );
				tAssTankFishDao.saveOrUpdate( entity );
				
				TFish tFish = tFishDao.findByPk( livestockBean.getId() );
				TTank tTank = tTankDao.findByPk( livestockBean.getTankId() );
				if (tFish.getGhMax()!=null) tTank.setGhMax( tTank.getGhMax()!=null && tTank.getGhMax()>tFish.getGhMax() ? tFish.getGhMax() : tTank.getGhMax() );
				if (tFish.getGhMin()!=null) tTank.setGhMin( tTank.getGhMin()!=null && tTank.getGhMin()>tFish.getGhMin() ? tFish.getGhMin() : tTank.getGhMin() );
				if (tFish.getPhMax()!=null) tTank.setPhMax( tTank.getPhMax()!=null && tTank.getPhMax()>tFish.getPhMax() ? tFish.getPhMax() : tTank.getPhMax() );	
				if (tFish.getPhMin()!=null) tTank.setPhMin( tTank.getPhMin()!=null && tTank.getPhMin()>tFish.getPhMin() ? tFish.getPhMin() : tTank.getPhMin() );
				if (tFish.getTemperatureMax()!=null) tTank.setTemperatureMax( tTank.getTemperatureMax()!=null && tTank.getTemperatureMax()>tFish.getTemperatureMax() ? tFish.getTemperatureMax() : tTank.getTemperatureMax() );
				if (tFish.getTemperatureMin()!=null) tTank.setTemperatureMin( tTank.getTemperatureMin()!=null && tTank.getTemperatureMin()>tFish.getTemperatureMin() ? tFish.getTemperatureMin() : tTank.getTemperatureMin() );
				tTankDao.saveEntity(tTank);
				
			} else if ( livestockBean.getType().equals("Plant") ) {					/** AGGIUNGO PIANTA **/
				
				TAssTankPlant entity = new TAssTankPlant();
				entity.setIdPlant( livestockBean.getId() );
				entity.setIdTank( livestockBean.getTankId() );
				tAssTankPlantDao.saveOrUpdate( entity );
				
				TPlant tPlant = tPlantDao.findByPk( livestockBean.getId() );
				TTank tTank = tTankDao.findByPk( livestockBean.getTankId() );
				if (tPlant.getGhMax()!=null) tTank.setGhMax( tTank.getGhMax()!=null && tTank.getGhMax()>tPlant.getGhMax() ? tPlant.getGhMax() : tTank.getGhMax() );
				if (tPlant.getGhMin()!=null) tTank.setGhMin( tTank.getGhMax()!=null && tTank.getGhMin()>tPlant.getGhMin() ? tPlant.getGhMin() : tTank.getGhMin() );
				if (tPlant.getPhMax()!=null) tTank.setPhMax( tTank.getPhMax()!=null && tTank.getPhMax()>tPlant.getPhMax() ? tPlant.getPhMax() : tTank.getPhMax() );
				if (tPlant.getPhMin()!=null) tTank.setPhMin( tTank.getPhMin()!=null && tTank.getPhMin()>tPlant.getPhMin() ? tPlant.getPhMin() : tTank.getPhMin() );
				if (tPlant.getKhMax()!=null) tTank.setKhMax( tTank.getKhMax()!=null && tTank.getKhMax()>tPlant.getKhMax() ? tPlant.getKhMax() : tTank.getKhMax() );
				if (tPlant.getKhMin()!=null) tTank.setKhMin( tTank.getKhMin()!=null && tTank.getKhMin()>tPlant.getKhMin() ? tPlant.getKhMin() : tTank.getKhMin() );
				if (tPlant.getTemperatureMax()!=null) tTank.setTemperatureMax( tTank.getTemperatureMax()!=null && tTank.getTemperatureMax()>tPlant.getTemperatureMax() ? tPlant.getTemperatureMax() : tTank.getTemperatureMax() );
				if (tPlant.getTemperatureMin()!=null) tTank.setTemperatureMin( tTank.getTemperatureMin()!=null && tTank.getTemperatureMin()>tPlant.getTemperatureMin() ? tPlant.getTemperatureMin() : tTank.getTemperatureMin() );
				tTankDao.saveEntity(tTank);
			}
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("saveLivestock >>>>>>>>>>>> " + e, e);
			throw(e);
		}
	}
	
	@Override
	@Transactional(readOnly=false,rollbackFor=Exception.class)
	public void deleteLivestock( LivestockBean livestockBean ) throws Exception {
		
		try {
			
			if ( livestockBean.getType().equals("Fish"))							/** ELIMINO PESCE **/
				tAssTankFishDao.deleteByLivestockId(livestockBean.getId());
			else if ( livestockBean.getType().equals("Plant") ) 					/** ELIMINO PIANTA **/
				tAssTankPlantDao.deleteByLivestockId(livestockBean.getId());
			
			/** Verifico se la vasca e' vuota **/
			List<TAssTankFish> listFish = tAssTankFishDao.findByIdTank( livestockBean.getTankId() );
			if(ListUtils.listIsEmpty(listFish)) {
				List<TAssTankPlant> listPlant = tAssTankPlantDao.findByIdTank( livestockBean.getTankId() );
				if(ListUtils.listIsEmpty(listPlant)) {
					/** La vasca e' vuota ed elimino i parametri **/
					TTank entityTank = tTankDao.findByPk( livestockBean.getTankId() );
					entityTank.setPhMax( null );
					entityTank.setPhMin( null );
					entityTank.setGhMax( null );
					entityTank.setGhMin( null );
					entityTank.setKhMax( null );
					entityTank.setKhMin( null );
					entityTank.setTemperatureMax( null );
					entityTank.setTemperatureMin( null );
				}
			}
			
			logger.info("Query eseguita correttamente");
		} catch(Exception e){
			logger.error("deleteLivestock >>>>>>>>>>>> " + e, e);
			throw(e);
		}
	}
}
